#include "BME280.hpp"
#include "BPCanaly.hpp"
#include "DS3231.hpp"
#include <EEPROM.h>
#include "SHTC3_BETA0_1.hpp"
#define BPCPIN 7
#define BPCENB 6
#define RETPPM(A) 116.60*pow(A/76.63,-2.77)

uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
int8_t dig_H1;
int16_t dig_H2;
int8_t dig_H3;
int16_t dig_H4;
int16_t dig_H5;
int8_t dig_H6;
timeSET RECV;//存储时间
byte SYNCTIME=EEPROM.read(4);//从内部EEPROM的第四单元读取自动更新时间
bool IsUPDATED;//记录是否已经更新
int UpdateSuccessTime;//记录成功对时次数
TIMESTAMP LASTUPDATETIME;//最后一次对时时间

int AutoSYNCtime(TIMESTAMP* RETURNTO)//自动和BPC电台对时
{
  digitalWrite(6,LOW);//启用BPC模块
  TIMESTAMP SOURCE;
  timeSET STFORM;
  char METADATA[20];
  init_pin(BPCPIN,BPCENB);
  ANALY(METADATA,BPCPIN,1);//分析数据，目前开启调试模式
  SOURCE=TransferToStandardForm(METADATA,1);
  if((SOURCE.VERIFY1==0) && (SOURCE.VERIFY2==0))//如果获取的BPC数据无误，则设置DS3231
  {
    if((SOURCE.SECOND==0) || (SOURCE.SECOND==20))
    SOURCE.SECOND+=20;//由于BPC的时间是开始发送的时间，因此正确的时间是BPC播报的时间+20秒
    else//若从40秒开始
    {
      SOURCE.SECOND=0;
      if(SOURCE.MINUTE==59)//如果此时是从40秒开始的，那么就意味着分钟+1，倘若分钟是59分，则小时+1
      {
        SOURCE.HOUR++;
        SOURCE.MINUTE=0;
      }
      else
      SOURCE.MINUTE++;
    }
    STFORM.year=SOURCE.YEAR;
    STFORM.day=SOURCE.DAY;
    STFORM.month=SOURCE.MONTH;
    STFORM.week=SOURCE.WEEK;

    STFORM.HOUR=SOURCE.HOUR;
    STFORM.MIN=SOURCE.MINUTE;
    STFORM.SEC=SOURCE.SECOND;
    SETTIME(&STFORM);
    return 0;
    *RETURNTO=SOURCE;//返回接收到的数据
  }
  else//否则不执行
  return 1; 
}

void BME280INIT()//初始化气压监测模块
{
  SETUPDEV();
  _readTrim(&dig_T1,&dig_T2,&dig_T3,&dig_P1,&dig_P2,&dig_P3,&dig_P4,&dig_P5,&dig_P6,&dig_P7,&dig_P8,&dig_P9,&dig_H1,&dig_H2,&dig_H3,&dig_H4,&dig_H5,&dig_H6);
}

void GETDATABME280(double &temp_act,double &press_act,double &hum_act)//从气压监测模块获取数据
{
  unsigned long int pres_raw;
  unsigned long int temp_raw;
  unsigned long int hum_raw;

  signed long int t_fine;
  signed long int adc_P;

  temp_act = 0.0, press_act = 0.0,hum_act=0.0;
  signed long int temp_cal;
  unsigned long int press_cal,hum_cal;

  _readData(&pres_raw,&temp_raw,&hum_raw);

    temp_cal = _calibration_T(temp_raw,&t_fine,&dig_T1,&dig_T2,&dig_T3);
    press_cal = _calibration_P(pres_raw,t_fine,dig_P1,dig_P2,dig_P3,dig_P4,dig_P5,dig_P6,dig_P7,dig_P8,dig_P9);
    hum_cal = _calibration_H(hum_raw,t_fine,dig_H1,dig_H2,dig_H3,dig_H4,dig_H5,dig_H6);
    temp_act = (double)temp_cal / 100.0;
    press_act = (double)press_cal / 100.0;
    hum_act = (double)hum_cal / 1024.0;
}

int ReadLUX()//读取亮度
{
  return(analogRead(A0));
}

void setup()
{
  pinMode(BPCPIN,INPUT);
  pinMode(BPCENB,OUTPUT);
  digitalWrite(BPCENB,LOW);
  Serial.begin(9600);
  BME280INIT();
  pinMode(A0,INPUT);
  pinMode(A2,INPUT);
  WakeupDEFICE();
}

void UploadReport(int mode,int beacon)//mode：传输模式，beacon：传输间隔时间
{
  double PRESSURE=0.0;//气压
  double TEMP=0.0;//温度
  double HUMI=0.0;//湿度
  RECV=RECTIME();
  TEMPDATA TMP=ReadDATACMD();
  FinalDATA GEL=GetFinalDATA(TMP);
  GETDATABME280(TEMP,PRESSURE,HUMI);
  HUMI=GEL.HUMI;
  float PPM=RETPPM((double)analogRead(A2));
  switch(mode)
  {
    case 0://纯报文格式
    {
      for(int i=0;i<10;i++)
      {   
          RECV=RECTIME();
          PPM=RETPPM((double)analogRead(A2));
          Serial.print((2000+RECV.year));
          Serial.print('-');

          if(RECV.month>=10)
          Serial.print(RECV.month);
          else
          {
          Serial.print('0');
          Serial.print(RECV.month);
          }
          Serial.print('-');

          if(RECV.day>=10)
          Serial.print(RECV.day);
          else
          {
          Serial.print('0');
          Serial.print(RECV.day);
          }
          
          //Serial.print('-');
          //Serial.print(RECV.week);
          //Serial.print(' ');
          if(RECV.HOUR>=10)
          Serial.print(RECV.HOUR);
          else
          {
            Serial.print('0');
            Serial.print(RECV.HOUR);
          }
          Serial.print(':');

          if(RECV.MIN>=10)
          Serial.print(RECV.MIN);
          else
          {
            Serial.print('0');
            Serial.print(RECV.MIN);
          }
          Serial.print(':');

          if(RECV.SEC>=10)
          Serial.print(RECV.SEC);
          else
          {
            Serial.print('0');
            Serial.print(RECV.SEC);
          }
          switch(RECV.week)
            {
              case 1:
              {
                Serial.print("MON.");//12空
                break;
              }
              case 2:
              {
                Serial.print("TUE.");
                break;
              }
              case 3:
              {
                Serial.print("WED.");
                break;
              }
              case 4:
              {
                Serial.print("THU.");
                break;
              }
              case 5:
              {
                Serial.print("FRI.");
                break;
              }
              case 6:
              {
                Serial.print("SAT.");
                break;
              }
              case 7:
              {
                Serial.print("SUN.");
                break;
              }
              default:
              {
                Serial.print("N/A");
                break;
              }
            }
            Serial.print("GAS:");
            Serial.print(PPM);
            Serial.print("/PPM");
            delay(beacon);
      }
      for(int i=0;i<10;i++)
      {
        FinalDATA GEL=GetFinalDATA(TMP);
        GETDATABME280(TEMP,PRESSURE,HUMI);
        HUMI=GEL.HUMI;
        if(PRESSURE<1000)
        {
          Serial.print(' ');
          Serial.print(PRESSURE);
        }
        else
        Serial.print(PRESSURE);
        Serial.print(" PA");
        Serial.print("T:");
        Serial.print(TEMP);
        Serial.write(0x00);
        if(TEMP<10)
        Serial.print(' ');

        Serial.print("HUMI:");
        Serial.print(HUMI);
        Serial.print("      ");
        delay(beacon);
      }
      break;
    }
     case 1://带标签的报文
     {
        Serial.println("TIME:");
        Serial.print("20");
        Serial.print(RECV.year);
        Serial.print("-");
        Serial.print(RECV.month);
        Serial.print('-');
        Serial.print(RECV.day);
        Serial.print(' ');
        PPM=RETPPM((double)analogRead(A2));
        //打印年月日
        switch(RECV.week)
        {
          case 1:
          {
            Serial.print("MON.");
            break;
          }
          case 2:
          {
            Serial.print("TUE.");
            break;
          }
          case 3:
          {
            Serial.print("WED.");
            break;
          }
          case 4:
          {
            Serial.print("THU.");
            break;
          }
          case 5:
          {
            Serial.print("FRI.");
            break;
          }
          case 6:
          {
            Serial.print("SAT.");
            break;
          }
          case 7:
          {
            Serial.print("SUN.");
            break;
          }
          default:
          {
            Serial.print("N/A");
            break;
          }
        }
        //打印星期
        Serial.print(' ');
        Serial.print(RECV.HOUR);
        Serial.print(':');
        Serial.print(RECV.MIN);
        Serial.print(':');
        Serial.print(RECV.SEC);
        Serial.print('\n');

        Serial.print("ATMOSPHERE PRESSURE:");
        Serial.print(PRESSURE);
        Serial.print("MPA ATMOSPHERE TEMP:");
        Serial.print(TEMP);
        Serial.print("DEGREE\n");
        Serial.print("BRIGHTNESS:");
        Serial.println(ReadLUX());
        Serial.print(" HUMIDITY:");
        Serial.print(HUMI);
        Serial.print(" CRCSTATUS:");
        Serial.print(GEL.CRCSTATUS1);
        Serial.print(GEL.CRCSTATUS2);
        Serial.print('\n');
        
        Serial.print("CO2DEC:");
        Serial.print(PPM);
        Serial.println("/PPM");
        delay(beacon);
        break;
     }
    }
  }

void sync(int attemptTimes)
{
  for(int i=0;i<attemptTimes;i++)
  {
      if(AutoSYNCtime(&LASTUPDATETIME))
        Serial.println("SYNC FAIL!\n");
      else
      {
        Serial.println("SYNC SUCCESS!\n");
        UpdateSuccessTime++;
        break;
      }
    }
    digitalWrite(6,HIGH); //重新关闭BPC模块
}

void loop()
{
  char* read[50];
  int SYNCTIME=EEPROM.read(4);//从内部EEPROM的第四单元读取自动更新时间
  digitalWrite(6,HIGH);//暂时屏蔽BPC接收功能
  while(1)
  {
    UploadReport(EEPROM.read(5),500);

    if(RECV.HOUR==SYNCTIME && IsUPDATED==0)//到时自动更新
    {
      sync(5);
      IsUPDATED=1;
    }
    if(RECV.HOUR==(SYNCTIME+1))//如果经过更新时间一个小时，则重新将更新记录清空
    IsUPDATED=0;

    if(Serial.available()>0)
    {
      delay(100);
      for(int i=0;i<50;i++)
      read[i]=Serial.read(); 

      while(Serial.available()>0)
      Serial.read();//清除串口标志

      if(read[0]=='S' && read[1]=='Y' && read[2]=='N')//格式：SYN X
      {
        int attempt=read[4]-0x30;
        Serial.println("BPC SYNC");
        sync(attempt);
      }
      if(read[0]=='S' && read[1]=='E' && read[2]=='T' && read[3]=='M')//SETM
      {
        Serial.println("TIME SET");
        DebugDS3231BYSERIAL();
      }

      if(read[0]=='S' && read[1]=='E' && read[2]=='T' && read[3]=='A')//SETA X
      {
        Serial.println("MEM SET");
        EEPROM.write(4,(read[5]-0x30));
        SYNCTIME=EEPROM.read(4);
        Serial.print("AUTO UPDATE HAS BEEN SET IN:");
        Serial.println(SYNCTIME);
      }

      if(read[0]=='V' && read[1]=='I' && read[2]=='E' && read[3]=='W')//VIEW
      {
        Serial.print("UPDATE SUCCESS TIME(S):");
        Serial.println(UpdateSuccessTime);
      }
      if(read[0]=='C' && read[1]=='H' && read[2]=='K' && read[3]=='T')//CHKT
      {
        Serial.print("LAST UPDATE TIME IS:");
        Serial.print((2000+LASTUPDATETIME.YEAR));
        Serial.print('-');
        Serial.print(LASTUPDATETIME.MONTH);
        Serial.print('-');
        Serial.print(LASTUPDATETIME.DAY);
        Serial.print(' ');
        Serial.print(LASTUPDATETIME.HOUR);
        Serial.print(':');
        Serial.print(LASTUPDATETIME.MINUTE);
        Serial.print(':');
        Serial.println(LASTUPDATETIME.SECOND);
      }
      if(read[0]=='I' && read[1]=='N' && read[2]=='F' && read[3]=='O')//INFO
      {
        Serial.println("ENVIRONMENT DETECTOR-TAKIMOT0");
        Serial.println("FIRMWARE VERSION:1.0_FINAL");
        Serial.println("AUTHOR:TAKIMOT09116");
      }
      if(read[0]=='S' && read[1]=='E' && read[2]=='M' && read[3]=='O')//SEMO X
      {
        EEPROM.write(5,(read[5]-0x30));
        Serial.println("MODE OK!");
      }
      else
      {
        Serial.println("UNKNOWN COMMAND");
        Serial.println("COMMAND MENU:");
        Serial.println("SYN X:X IS THE ATTEMPT TIMES OF SYNC TIME FROM BPC");
        Serial.println("SETM:SET TIME");
        Serial.println("SETA:SET AUTO UPDATE TIME");
        Serial.println("VIEW:UPDATE SUCCEED TIMES");
        Serial.println("CHKT:LAST UPDATE TIME");
        Serial.println("INFO:CHECK THE FIRMWARE");
        delay(3000);
      }
    }
  }
}
